package Protocol;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * This class is to generate a symmetric key to protect private key on Server
 * 
 * @author HaoL
 * 
 */
public class PrivateKeyProtectorPBEKey {
	//private static char[] superUserPassword = "CLLL".toCharArray();
	public static byte[] salt = {
		 (byte)0xc8, (byte)0x73, (byte)0x41, (byte)0x8c,
	        (byte)0x7e, (byte)0xd8, (byte)0xee, (byte)0x89
	};
		
	private static final int KEYLENGTH = 128;
	private static final int ITERATION = 20;
	private static final String CIPHERALGORITHM = "AES/CBC/PKCS5Padding";
	private SecretKey secretKey = null;
	private Cipher cipher = null;
	
	/**
	 * 
	 * @param superpassword
	 * @throws InvalidKeySpecException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchPaddingException
	 */
	public PrivateKeyProtectorPBEKey(char[] superpassword) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException
	{
		SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
		KeySpec pbekeySpec = new PBEKeySpec(superpassword, salt, ITERATION, KEYLENGTH);
		secretKey =  new SecretKeySpec(factory.generateSecret(pbekeySpec).getEncoded(), "AES");
		cipher = Cipher.getInstance(CIPHERALGORITHM);
	}
	
	public PBEStorage getCipher(byte[] privateKey) throws Exception {
		//if any of them is null value, constructor is not working.
		if (secretKey == null || cipher == null)
		{
			throw new Exception("Encrypt: No secretkey or cipher generated by constructor");
		}
		cipher.init(Cipher.ENCRYPT_MODE, secretKey);

		return new PBEStorage(
				cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV(), 
				cipher.doFinal(privateKey));
	}

	public byte[] getPlainTest(byte[] data, byte[] iv) throws Exception {
		
		if (secretKey == null || cipher == null) {
			throw new Exception("Encrypt: No secretkey or cipher generated by constructor");
		}
		
		cipher.init(Cipher.DECRYPT_MODE, secretKey,
					new IvParameterSpec(iv));
		

		return cipher.doFinal(data);
	}
	
	public SecretKey getKey()
	{
		return this.secretKey;
	}
	
	public static void main(String argsp[]) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, Exception
	{
		PrivateKeyProtectorPBEKey testProtector = new PrivateKeyProtectorPBEKey("hao".toCharArray());
		String message = "Testing String written by Hao";
		byte[] messageByte = message.getBytes();
		System.out.println("This is the hashCode:"+ testProtector.getKey().hashCode());
		PBEStorage storage = testProtector.getCipher(messageByte);
		System.out.println("Here is the encrypted and decrypted one:"+ 
				new String(testProtector.getPlainTest(storage.getCiphertext(),storage.getIV())));
	}

}
